/*
 * timeago: a jQuery plugin, version: 0.9.3 (2011-01-21)
 * @requires jQuery v1.2.3 or later
 *
 * Timeago is a jQuery plugin that makes it easy to support automatically
 * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
 *
 * For usage and examples, visit:
 * http://timeago.yarp.com/
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2008-2011, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
 */
(function($) {
  $.timeago = function(timestamp) {
    if (timestamp instanceof Date) {
      return inWords(timestamp);
    } else if (typeof timestamp === "string") {
      return inWords($.timeago.parse(timestamp));
    } else {
      return inWords($.timeago.datetime(timestamp));
    }
  };
  var $t = $.timeago;

  $.extend($.timeago, {
    settings: {
      refreshMillis: 60000,
      allowFuture: false,
      strings: {
        prefixAgo: null,
        prefixFromNow: null,
        suffixAgo: "geleden",
        suffixFromNow: "vanaf nu",
        seconds: "minder dan een minuut",
        minute: "ongeveer een minuut",
        minutes: "%d minuten",
        hour: "ongeveer een uur",
        hours: "%d uren",
        day: "een dag",
        days: "%d dagen",
        month: "ongeveer een maand",
        months: "%d maanden",
        year: "ongeveer een jaar",
        years: "%d jaren",
        numbers: []
      }
    },
    inWords: function(distanceMillis) {
      var $l = this.settings.strings;
      var prefix = $l.prefixAgo;
      var suffix = $l.suffixAgo;
      if (this.settings.allowFuture) {
        if (distanceMillis < 0) {
          prefix = $l.prefixFromNow;
          suffix = $l.suffixFromNow;
        }
        distanceMillis = Math.abs(distanceMillis);
      }

      var seconds = distanceMillis / 1000;
      var minutes = seconds / 60;
      var hours = minutes / 60;
      var days = hours / 24;
      var years = days / 365;

      function substitute(stringOrFunction, number) {
        var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
        var value = ($l.numbers && $l.numbers[number]) || number;
        return string.replace(/%d/i, value);
      }

      var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
        seconds < 90 && substitute($l.minute, 1) ||
        minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
        minutes < 90 && substitute($l.hour, 1) ||
        hours < 24 && substitute($l.hours, Math.round(hours)) ||
        hours < 48 && substitute($l.day, 1) ||
        days < 30 && substitute($l.days, Math.floor(days)) ||
        days < 60 && substitute($l.month, 1) ||
        days < 365 && substitute($l.months, Math.floor(days / 30)) ||
        years < 2 && substitute($l.year, 1) ||
        substitute($l.years, Math.floor(years));

      return $.trim([prefix, words, suffix].join(" "));
    },
    parse: function(iso8601) {
      var s = $.trim(iso8601);
      s = s.replace(/\.\d\d\d+/,""); // remove milliseconds
      s = s.replace(/-/,"/").replace(/-/,"/");
      s = s.replace(/T/," ").replace(/Z/," UTC");
      s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
      return new Date(s);
    },
    datetime: function(elem) {
      // jQuery's `is()` doesn't play well with HTML5 in IE
      var isTime = $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
      var iso8601 = isTime ? $(elem).attr("datetime") : $(elem).attr("title");
      return $t.parse(iso8601);
    }
  });

  $.fn.timeago = function() {
    var self = this;
    self.each(refresh);

    var $s = $t.settings;
    if ($s.refreshMillis > 0) {
      setInterval(function() { self.each(refresh); }, $s.refreshMillis);
    }
    return self;
  };

  function refresh() {
    var data = prepareData(this);
    if (!isNaN(data.datetime)) {
      $(this).text(inWords(data.datetime));
    }
    return this;
  }

  function prepareData(element) {
    element = $(element);
    if (!element.data("timeago")) {
      element.data("timeago", { datetime: $t.datetime(element) });
      var text = $.trim(element.text());
      if (text.length > 0) {
        element.attr("title", text);
      }
    }
    return element.data("timeago");
  }

  function inWords(date) {
    return $t.inWords(distance(date));
  }

  function distance(date) {
    return (new Date().getTime() - date.getTime());
  }

  // fix for IE6 suckage
  document.createElement("abbr");
  document.createElement("time");
}(jQuery));

var url = 'http://www.hikle.nl/';

var zeropad = function (num) {
  return ((num < 10) ? '0' : '') + num;
};
var iso8601 = function (date) {
  return date.getUTCFullYear()
    + "-" + zeropad(date.getUTCMonth()+1)
    + "-" + zeropad(date.getUTCDate())
    + "T" + zeropad(date.getUTCHours())
    + ":" + zeropad(date.getUTCMinutes())
    + ":" + zeropad(date.getUTCSeconds()) + "Z";
};

function loadNumbers() {
  jQuery.timeago.settings.strings.numbers = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"];
}
function unloadNumbers() {
  jQuery.timeago.settings.strings.numbers = [];
}

function loadMillis() {
  var millisSubstitution = function(number, millis) { return millis + " milliseconds"; };
  jQuery.timeago.settings.strings = {
    suffixAgo: "ago",
    suffixFromNow: "from now",
    seconds: millisSubstitution,
    minute: millisSubstitution,
    minutes: millisSubstitution,
    hour: millisSubstitution,
    hours: millisSubstitution,
    day: millisSubstitution,
    days: millisSubstitution,
    month: millisSubstitution,
    months: millisSubstitution,
    year: millisSubstitution,
    years: millisSubstitution
  };
}

function loadYoungOldYears() {
  jQuery.extend(jQuery.timeago.settings.strings, {
    years: function(value) { return (value < 21) ? "%d young years" : "%d old years"; }
  });
}

function ucwords(str){
    return (str + '').replace(/^([a-z])|\s+([a-z])/g, function ($1) {
        return $1.toUpperCase();
    });
}

var keys = {
	backspace: 8,
	tab: 9,
	enter: 13,
	escape: 27,
	space: 32,
	page_up: 33,
	page_down: 34,
	end: 35,
	home: 36,
	left: 37,
	up: 38,
	right: 39,
	down: 40,
	numpad_enter: 108,
	comma: 188
};

var positions = {
	before: 0,
	after: 1,
	end: 2
};

// Global token input plugin.

(function ($) {
var defaultSettings = {
    method: 'POST',
    contentType: 'json',
    queryParam: 'keyword',
    searchDelay: 400,
    minChars: 2,
    propertyToSearch: "name",
    jsonContainer: null,
    searchingText: "Bezig met zoeken...",
    deleteText: "&times;",
    tokenLimit: null,
    tokenDelimiter: ",",
    preventDuplicates: false,
    tokenValue: "id",
    prePopulate: null,
    processPrePopulate: false,
    idPrefix: "tokenInput",
    resultsFormatter: function(item){
    	return '<li>' + ucwords(item[this.propertyToSearch]) + '</li>';
    },
    tokenFormatter: function(item){
   		return '<li><p>' + ucwords(item[this.propertyToSearch]) + '</p></li>';
   	},
    onResult: null,
    onAdd: null,
    onDelete: null,
    onReady: null,
    onSearching: null
};

var defaultClasses = {
    tokenList: 'tokenInputList',
    token: 'token',
    tokenDelete: 'tokenDelete',
    selectedToken: 'selectedToken',
    highlightedToken: 'highlightedToken',
    dropdown: 'aDropdown',
    dropdownItem: 'aDropdownItem',
    selectedDropdownItem: 'aDropdownItemSelected',
    inputToken: 'tokenInputInputToken'
};

var methods = {
    init: function(urlDataOrFunction, options) {
        var settings = $.extend({}, defaultSettings, options || {});

        return this.each(function () {
            $(this).data("tokenInputObject", new $.TokenList(this, urlDataOrFunction, settings));
        });
    },
    clear: function() {
        this.data("tokenInputObject").clear();
        return this;
    },
    add: function(item) {
        this.data("tokenInputObject").add(item);
        return this;
    },
    remove: function(item) {
        this.data("tokenInputObject").remove(item);
        return this;
    },
    get: function() {
    	return this.data("tokenInputObject").getTokens();
   	},
   	reload: function(extraData) {
   		this.data('tokenInputObject').reload(extraData);
   	}
}

// jQuery plugin.
$.fn.tokenInput = function (method) {
    if(methods[method]) {
        return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    } else {
        return methods.init.apply(this, arguments);
    }
};

// Token input class.
$.TokenList = function (input, url_or_data, settings) {
    settings.url = url_or_data;

    var url = computeURL();
    
    this.reload = function(extraData){
   		settings.extraData = extraData;
    }

    if(settings.crossDomain === undefined) {
        if(url.indexOf("://") === -1) {
            settings.crossDomain = false;
        } else {
            settings.crossDomain = (location.href.split(/\/+/g)[1] !== url.split(/\/+/g)[1]);
        }
    }
    
    // Get defaultClasses.
    if(settings.classes) {
        settings.classes = $.extend({}, defaultClasses, settings.classes);
    } else if(settings.theme) {
        settings.classes = {};
        $.each(defaultClasses, function(key, value) {
            settings.classes[key] = value + "-" + settings.theme;
        });
    } else {
        settings.classes = defaultClasses;
    }
    
    var savedTokens = [];
    var tokenCount = 0;
    var timeout;
    var inputVal;
    var cache = new Cache();
   	var placeHolder = $(input).attr('placeholder');
   	var tooltip = $(input).attr('tooltip');
   	var inputTabIndex = $(input).attr('tabindex');
    
    var inputBox = $('<input type="text" autocomplete="off">')
    .css({
        outline: 'none'
    })
    .val(placeHolder)
    .attr('id', settings.idPrefix + input.id)
    .focus(function () {
    	if(inputBox.val() === placeHolder){
    		inputBox.val('');
    	} else {
    		inputBox.removeClass('placeholder');
    	}
    	
		if(tooltip && tooltip.length){
			showTooltip(inputBox);
		}
    })
    .blur(function () {
    	hideTooltips();
    	
    	if(inputBox.val() === '' && tokenCount === 0){
    		inputBox.addClass('placeholder');
    		inputBox.val(placeHolder);
    	}
    
    	dropdown.hide();
    	
		if(tooltip && tooltip.length){
			hideTooltips();
		}
    })
    .bind("keyup keydown blur update", resizeInput)
    .keydown(function (event) {    
        var previousToken;
        var nextToken;

        switch(event.keyCode) {
            case keys.left:
            case keys.right:
            case keys.up:
            case keys.down:
                if(!$(this).val()) {
                    previousToken = inputToken.prev();
                    nextToken = inputToken.next();

                    if((previousToken.length && previousToken.get(0) === selectedToken) || (nextToken.length && nextToken.get(0) === selectedToken)) {
                        if(event.keyCode === keys.left || event.keyCode === keys.up) {
                            deselectToken($(selectedToken), positions.before);
                        } else {
                            deselectToken($(selectedToken), positions.after);
                        }
                    } else if((event.keyCode === keys.left || event.keyCode === keys.up) && previousToken.length) {
                        selectToken($(previousToken.get(0)));
                    } else if((event.keyCode === keys.right || event.keyCode === keys.down) && nextToken.length) {
                        selectToken($(nextToken.get(0)));
                    }
                } else {
                    var dropdownItem = null;

                    if(event.keyCode === keys.down || event.keyCode === keys.right) {
                        dropdownItem = $(selectedDropdownItem).next();
                    } else {
                        dropdownItem = $(selectedDropdownItem).prev();
                    }

                    if(dropdownItem.length) {
                        selectDropdownItem(dropdownItem);
                    }
                    return false;
                }
                break;

            case keys.backspace:
                previousToken = inputToken.prev();

                if(!$(this).val().length) {
                    if(selectedToken) {
                        deleteToken($(selectedToken));
                        hiddenInput.change();
                    } else if(previousToken.length) {
                        selectToken($(previousToken.get(0)));
                    }

                    return false;
                } else if($(this).val().length === 1) {
                    hideDropdown();
                } else {
                    setTimeout(function(){doSearch();}, 5);
                }
                break;

            case keys.enter:
            case keys.numpadEnter:
            case keys.comma:
              if(selectedDropdownItem) {
                addToken($(selectedDropdownItem).data("tokeninput"));
                hiddenInput.change();
                return false;
              }
              break;

            case keys.escape:
              hideDropdown();
              return true;

            default:
                if(String.fromCharCode(event.which)) {
					if($(this).attr('id') === 'tokenInputcaTag' && $(this).val().length >= 10){
						return false;
					}
                
                	inputBox.removeClass('placeholder');
                
                    setTimeout(function(){
                    	doSearch();
                    }, 5);
                }
                break;
        }
	});
	
	if(inputTabIndex){
		inputBox.attr('tabindex', inputTabIndex);
	}
	
	if(tooltip && tooltip.length){
		inputBox.attr('tooltip', tooltip);
	}
        
    if(placeHolder && placeHolder.length){
    	inputBox.addClass('placeholder');
    }

	var hiddenInput = $(input)
	.hide()
	.val("")
	.focus(function () {
	inputBox.focus();
	})
	.blur(function () {
	inputBox.blur();
	});
                           
    var selectedToken = null;
    var selectedTokenIndex = 0;
    var selectedDropdownItem = null;
    
    var tokenList = $("<ul />")
        .addClass(settings.classes.tokenList)
        .attr("id", settings.classes.tokenList + input.id)
        .click(function (event) {
            var li = $(event.target).closest("li");
            if(li && li.get(0) && $.data(li.get(0), "tokeninput")) {
                toggleSelectToken(li);
            } else {
                if(selectedToken) {
                    deselectToken($(selectedToken), positions.end);
                }

                inputBox.focus();
            }
        })
        .mouseover(function (event) {
            var li = $(event.target).closest("li");
            if(li && selectedToken !== this) {
                li.addClass(settings.classes.highlightedToken);
            }
        })
        .mouseout(function (event) {
            var li = $(event.target).closest("li");
            if(li && selectedToken !== this) {
                li.removeClass(settings.classes.highlightedToken);
            }
        })
        .insertBefore(hiddenInput);
        
    var inputToken = $("<li />")
        .addClass(settings.classes.inputToken)
        .appendTo(tokenList)
        .append(inputBox);
        
    var dropdown = $("<div>")
        .addClass(settings.classes.dropdown)
        .attr("id", settings.classes.dropdown + input.id)
        .appendTo("body")
        .hide();
        
    var inputResizer = $("<tester/>")
        .insertAfter(inputBox)
        .css({
            position: "absolute",
            top: -9999,
            left: -9999,
            width: "auto",
            fontSize: inputBox.css("fontSize"),
            fontFamily: inputBox.css("fontFamily"),
            fontWeight: inputBox.css("fontWeight"),
            letterSpacing: inputBox.css("letterSpacing"),
            whiteSpace: "nowrap"
        });
        
    hiddenInput.val('');
    var liData = settings.prePopulate || hiddenInput.data("pre");
    if(settings.processPrePopulate && $.isFunction(settings.onResult)) {
        liData = settings.onResult.call(hiddenInput, liData);
    }
    if(liData && liData.length) {
        $.each(liData, function (index, value) {
            insertToken(value);
            checkTokenLimit();
        });
    }
    
    if($.isFunction(settings.onReady)) {
        settings.onReady.call();
    }

    this.clear = function() {
        tokenList.children("li").each(function() {
            if ($(this).children("input").length === 0) {
                deleteToken($(this));
            }
        });
    }

    this.add = function(item) {
        addToken(item);
    }

    this.remove = function(item) {
        tokenList.children("li").each(function() {
            if ($(this).children("input").length === 0) {
                var currToken = $(this).data("tokeninput");
                var match = true;
                for (var prop in item) {
                    if (item[prop] !== currToken[prop]) {
                        match = false;
                        break;
                    }
                }
                if (match) {
                    deleteToken($(this));
                }
            }
        });
    }
    
    this.getTokens = function() {
   		return savedTokens;
   	}
   	
    function checkTokenLimit() {
        if(settings.tokenLimit !== null && tokenCount >= settings.tokenLimit) {
            inputBox.hide();
            hideDropdown();
            return;
        }
    }

    function resizeInput() {
        if(inputVal === (inputVal = inputBox.val())) {return;}
        
        var escaped = inputVal.replace(/&/g, '&amp;').replace(/\s/g,' ').replace(/</g, '&lt;').replace(/>/g, '&gt;');
        inputResizer.html(escaped);
        inputBox.width(inputResizer.width() + 30);
    }
    
    function insertToken(item) {
        var thisToken = settings.tokenFormatter(item);
        thisToken = $(thisToken)
          .addClass(settings.classes.token)
          .insertBefore(inputToken);
          
          $("<span>" + settings.deleteText + "</span>")
            .addClass(settings.classes.tokenDelete)
            .appendTo(thisToken)
            .click(function () {
                deleteToken($(this).parent());
                hiddenInput.change();
                return false;
            });
            
        var token_data = {'id': item.id};
        token_data[settings.propertyToSearch] = item[settings.propertyToSearch];
        
        if(item.friendUserId){
        	token_data['friendUserId'] = item.friendUserId;
        }

        
        $.data(thisToken.get(0), "tokeninput", item);
        
        savedTokens = savedTokens.slice(0,selectedTokenIndex).concat([token_data]).concat(savedTokens.slice(selectedTokenIndex));
        selectedTokenIndex++;
       
        updateHiddenInput(savedTokens, hiddenInput);

        tokenCount++;
        
        if(settings.tokenLimit !== null && tokenCount >= settings.tokenLimit) {
            inputBox.hide();
            hideDropdown();
        }

        return thisToken;
    }
    
    function addToken (item) {
        var callback = settings.onAdd;
        
        if(tokenCount > 0 && settings.preventDuplicates) {
            var foundExistingToken = null;
            tokenList.children().each(function () {
                var existingToken = $(this);
                var existingData = $.data(existingToken.get(0), "tokeninput");
                if(existingData && existingData[settings.tokenValue] === item[settings.tokenValue]) {
                    foundExistingToken = existingToken;
                    return false;
                }
            });

            if(foundExistingToken) {
                selectToken(foundExistingToken);
                inputToken.insertAfter(foundExistingToken);
                inputBox.focus();
                return;
            }
        }
        
        if(settings.tokenLimit == null || tokenCount < settings.tokenLimit) {
            insertToken(item);
            checkTokenLimit();
        }
        
        inputBox.val('');
        hideDropdown();
        if($.isFunction(callback)) {
            callback.call(hiddenInput,item);
        }
    }
    
    function selectToken (token) {
        token.addClass(settings.classes.selectedToken);
        selectedToken = token.get(0);
        inputBox.val("");
        hideDropdown();
    }
    
    function deselectToken (token, position) {
        token.removeClass(settings.classes.selectedToken);
        selectedToken = null;

        if(position === positions.before) {
            inputToken.insertBefore(token);
            selectedTokenIndex--;
        } else if(position === positions.after) {
            inputToken.insertAfter(token);
            selectedTokenIndex++;
        } else {
            inputToken.appendTo(tokenList);
            selectedTokenIndex = tokenCount;
        }
        
        inputBox.focus();
    }
    
    function toggleSelectToken(token) {
        var previousSelectedToken = selectedToken;

        if(selectedToken) {
            deselectToken($(selectedToken), positions.end);
        }

        if(previousSelectedToken === token.get(0)) {
            deselectToken(token, positions.end);
        } else {
            selectToken(token);
        }
    }
    
    function deleteToken (token) {
        var token_data = $.data(token.get(0), "tokeninput");
        var callback = settings.onDelete;

        var index = token.prevAll().length;
        if(index > selectedTokenIndex) index--;
        
        token.remove();
        selectedToken = null;
        inputBox.focus();

        savedTokens = savedTokens.slice(0,index).concat(savedTokens.slice(index+1));
        if(index < selectedTokenIndex) selectedTokenIndex--;
        
        updateHiddenInput(savedTokens, hiddenInput);
        tokenCount -= 1;

        if(settings.tokenLimit !== null) {
            inputBox
                .show()
                .val("")
                .focus();
        }
        
        if($.isFunction(callback)) {
            callback.call(hiddenInput, token_data);
        }
    }

    function updateHiddenInput(savedTokens, hiddenInput) {
        var tokenValues = $.map(savedTokens, function(el){
            return el[settings.tokenValue];
        });
        
        hiddenInput.val(tokenValues.join(settings.tokenDelimiter));
    }
    
    function hideDropdown () {
        dropdown.hide().empty();
        selectedDropdownItem = null;
    }

    function showDropdown() {
    	// Hide all tooltips before we even show the dropdown.
    	hideTooltips();
    	
        dropdown
            .css({
                position: "absolute",
                top: $(tokenList).offset().top + $(tokenList).outerHeight(),
                left: $(tokenList).offset().left,
                zindex: 999
            })
            .show();
    }

    function showDropdownSearching() {
    	var callback = settings.onAdd;
    	
        if($.isFunction(callback)) {
            callback.call();
        }
    }

    // Populate the results dropdown with some results
    function populateDropdown(query, results) {
        if(results && results.length) {
            dropdown.empty();
            var dropdownUl = $("<ul>")
                .appendTo(dropdown)
                .mouseover(function (event) {
                    selectDropdownItem($(event.target).closest("li"));
                })
                .mousedown(function (event) {
                    addToken($(event.target).closest('li').data('tokeninput'));
                    hiddenInput.change();
                    return false;
                })
                .hide();

            $.each(results, function(index, value) {
                var li = settings.resultsFormatter(value);
                li = $(li).appendTo(dropdownUl);
                li.addClass(settings.classes.dropdownItem);

                if(index === 0) {
                    selectDropdownItem(li);
                }

                $.data(li.get(0), 'tokeninput', value);
            });

            showDropdown();
            dropdownUl.show();
        } else {
        	hideDropdown();
        }
    }

    // Highlight an item in the results dropdown
    function selectDropdownItem (item) {
        if(item) {
            if(selectedDropdownItem) {
                deselectDropdownItem($(selectedDropdownItem));
            }

            item.addClass(settings.classes.selectedDropdownItem);
            selectedDropdownItem = item.get(0);
        }
    }

    // Remove highlighting from an item in the results dropdown
    function deselectDropdownItem (item) {
        item.removeClass(settings.classes.selectedDropdownItem);
        selectedDropdownItem = null;
    }

    // Do a search and show the "searching" dropdown if the input is longer
    // than settings.minChars
    function doSearch() {
        var query = inputBox.val().toLowerCase();

        if(query && query.length) {
            if(selectedToken) {
                deselectToken($(selectedToken), positions.after);
            }

            if(query.length >= settings.minChars) {
                showDropdownSearching();
                clearTimeout(timeout);

                timeout = setTimeout(function(){
                    runSearch(query);
                }, settings.searchDelay);
            } else {
                hideDropdown();
            }
        }
    }

    // Do the actual search
    function runSearch(query) {
        var cacheKey = query + computeURL();
        var cachedResults = cache.get(cacheKey);
        if(cachedResults) {
            populateDropdown(query, cachedResults);
        } else {
            // Are we doing an ajax search or local data search?
            if(settings.url) {
                var url = computeURL();
                // Extract exisiting get params
                var ajaxParameters = {};
                ajaxParameters.data = {};
                
/*
                if(settings.extraData !== undefined){
	                $.each(settings.extraData, function(index, value){
	                	ajaxParameters.data[index] = value;
	                });
                }
*/
                
                ajaxParameters.url = url;

                // Prepare the request
                ajaxParameters.data[settings.queryParam] = query;
                ajaxParameters.type = settings.method;
                ajaxParameters.dataType = settings.contentType;
                
                if(settings.crossDomain) {
                    ajaxParameters.dataType = "jsonp";
                }
                
                // Attach the success callback
                ajaxParameters.success = function(results) {
                  if($.isFunction(settings.onResult)) {
                      results = settings.onResult.call(hiddenInput, results);
                  }
                  cache.add(cacheKey, settings.jsonContainer ? results[settings.jsonContainer] : results);

                  // only populate the dropdown if the results are associated with the active search query
                  if(inputBox.val().toLowerCase() === query) {
                      populateDropdown(query, settings.jsonContainer ? results[settings.jsonContainer] : results);
                  }
                };

                // Make the request
                $.ajax(ajaxParameters);
            } else if(settings.localData) {
                // Do the search through local data
                var results = $.grep(settings.localData, function (row) {
                    return row[settings.propertyToSearch].toLowerCase().indexOf(query.toLowerCase()) > -1;
                });

                if($.isFunction(settings.onResult)) {
                    results = settings.onResult.call(hiddenInput, results);
                }
                cache.add(cacheKey, results);
                populateDropdown(query, results);
            }
        }
    }

    // compute the dynamic URL
    function computeURL() {
        var url = settings.url;
        if(typeof settings.url == 'function') {
            url = settings.url.call();
        }
        return url;
    }
};
}(jQuery));

function showTooltip(element){
	hideTooltips();
	
    var tip = $('<div class="tooltip"><div class="tooltipInner"/></div>');
    tip.css({position: 'absolute', zIndex: 100000});
    tip.get(0).className = 'tooltip';
    var title = element.attr('tooltip');
    tip.find('.tooltipInner').text(title);
    tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).appendTo(document.body);
    var actualWidth = tip[0].offsetWidth, actualHeight = tip[0].offsetHeight;
    var id = element.attr('id');    
    var pos = $.extend({}, element.offset(), {width: document.getElementById(id).offsetWidth, height: document.getElementById(id).offsetHeight});
    tip.css({top: pos.top + pos.height, left: pos.left}).addClass('tooltipIcon');
    tip.css({visibility: 'visible'});
}

function hideTooltips(){
	$('.tooltip').remove();
}

function showNot(text){
	var notStayTime = 5000;
	var defaultOpacity = '0.7';
	var animating = false;
	var noticeWrapAll = (!jQuery('.noticeWrap').length) ? jQuery('<div></div>').addClass('noticeWrap').appendTo('body') : jQuery('.noticeWrap');
	var noticeItemOuter = jQuery('<div></div>').addClass('noticeItemWrapper');
	var noticeItemInner = jQuery('<div></div>').hide().addClass('noticeItem').appendTo(noticeWrapAll).html('<p>' + text + '</p>').show().wrap(noticeItemOuter);
	
	noticeItemInner.animate({opacity: defaultOpacity}, 1);
	
	setTimeout(function(){
	
		noticeItemInner.animate({opacity: '0'}, 600, function(){
			noticeItemInner.parent().remove();
		});
			
	}, notStayTime);
	
	noticeItemInner.mouseover(function(){
		noticeItemInner.animate({opacity: '1'}, 1);
	});
	
	noticeItemInner.mouseleave(function(){
		if(!animating){
			noticeItemInner.animate({opacity: defaultOpacity}, 1);
		}
	})
	
	noticeItemInner.click(function(){
	
		animating = true;
		noticeItemInner.animate({opacity: '0'}, 600, function(){
			noticeItemInner.parent().remove();
		});
	
	});
}

function Cache(){
    var maxSize = 500;
    var data = {};
    var size = 0;
    
    // Reset function.
	var flush = function(){
		data = {};
		size = 0;
	}
	
	// Add data function.
	this.add = function(keyword, results){
		if(size > maxSize){
			flush();
		}
		
		if(!data[keyword]){
			size += 1;
		}
		
		data[keyword] = results;
	}

	// Get data function.
	this.get = function(keyword){
		return data[keyword];
	}
};

// Initialize ui elements.
$(document).ready(function(){
	$('input[type="text"]').focus(function(){
		$(this).parents('.inputContainer').css({
			'background-color': '#FDFDFD'
		});
	}).blur(function(){
		$(this).parent().css({
			'background-color': '#FFFFFF'
		});
	});
	
	// Using live since some fields are generated by javascript eg. tokenlists.
	$('input[type="text"]').live('focus', function(){
		$(this).parents('.inputContainer').css({
			'background-color': '#FDFDFD'
		});
	});
	
	$('input[type="text"]').live('blur', function(){
		$(this).parents('.inputContainer').css({
			'background-color': '#FFFFFF'
		});
	});
	
	// Crossbrowsers placeholders.
	$('[placeholder]').focus(function() {
		var input = $(this);
		
		if(input.val() == input.attr('placeholder')){
			input.val('');
			input.removeClass('placeholder');
		}
	}).blur(function(){
		var input = $(this);
		
		if(input.val() == '' || input.val() == input.attr('placeholder')){
			input.addClass('placeholder');
			input.val(input.attr('placeholder'));
		}
	}).blur();
	
	$('.ui.inputContainer.friendSelector input').tokenInput('ajaj/searchFriends', {
		minChars: 2,
		searchDelay: 200,
		tokenValue: 'friendUserId',
		preventDuplicates: true,
		resultsFormatter: function(item){
			return '<li>' + ucwords(item['name']) + '</li>';
		}
	});
	
	// ui buttons focus
	$('.button').focus(function(){
		$(this).addClass('active');
		$(this).keydown(function(e){
			switch(e.keyCode){
				case keys.enter:
					$(this).click();
					return false;
					break;
			}
		});
	}).blur(function(){
		$(this).removeClass('active');
	});
	
	// Modal.
	$('.window .close').click(function (e) {
		e.preventDefault();
		$('#mask, .window').hide();
	});
	
	$('#mask').click(function () {
		$(this).hide();
		$('.window').hide();
	});
	
	var originalHeight = $('.window').height();
	var originalWidth = $('.window').width();
	
	// Resize the mask.
	window.onresize = function(event) {
		$('#mask').css({
			'width': '100%',
			'height': '100%'
		});

		$('.window').css('top',  $(window).height() / 2 - originalHeight / 2);
		$('.window').css('left', $(window).width() / 2 - originalWidth / 2);
	}
});